package cn.buildoncloud.labor.workermanapplet.util;

import org.apache.logging.log4j.util.Strings;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @Author CuiZibo
 * @Create 2018/2/6 13:56
 */
public class IdcardUtil {

    final static Map<Integer, String> zoneNum = new HashMap<Integer, String>();

    static {
        zoneNum.put(11, "北京");
        zoneNum.put(12, "天津");
        zoneNum.put(13, "河北");
        zoneNum.put(14, "山西");
        zoneNum.put(15, "内蒙古");
        zoneNum.put(21, "辽宁");
        zoneNum.put(22, "吉林");
        zoneNum.put(23, "黑龙江");
        zoneNum.put(31, "上海");
        zoneNum.put(32, "江苏");
        zoneNum.put(33, "浙江");
        zoneNum.put(34, "安徽");
        zoneNum.put(35, "福建");
        zoneNum.put(36, "江西");
        zoneNum.put(37, "山东");
        zoneNum.put(41, "河南");
        zoneNum.put(42, "湖北");
        zoneNum.put(43, "湖南");
        zoneNum.put(44, "广东");
        zoneNum.put(45, "广西");
        zoneNum.put(46, "海南");
        zoneNum.put(50, "重庆");
        zoneNum.put(51, "四川");
        zoneNum.put(52, "贵州");
        zoneNum.put(53, "云南");
        zoneNum.put(54, "西藏");
        zoneNum.put(61, "陕西");
        zoneNum.put(62, "甘肃");
        zoneNum.put(63, "青海");
        zoneNum.put(64, "宁夏");
        zoneNum.put(65, "新疆");
        zoneNum.put(71, "台湾");
        zoneNum.put(81, "香港");
        zoneNum.put(82, "澳门");
        zoneNum.put(91, "外国");
    }

    final static int[] PARITYBIT = {'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'};
    final static int[] POWER_LIST = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10,
            5, 8, 4, 2};

    public static String getAddress(String code) {
        if (Strings.isNotBlank(code)) {
            int i = Integer.parseInt(code.substring(0, 2));
            return zoneNum.get(i);
        }
        return null;
    }

    /**
     * 身份证验证
     *
     * @param s 号码内容
     * @return 是否有效 null和"" 都是false
     */
    public static boolean isIdcard(String s) {
        if (s == null || (s.length() != 15 && s.length() != 18))
            return false;
        final char[] cs = s.toUpperCase().toCharArray();
        //校验位数
        int power = 0;
        for (int i = 0; i < cs.length; i++) {
            if (i == cs.length - 1 && cs[i] == 'X')
                break;//最后一位可以 是X或x
            if (cs[i] < '0' || cs[i] > '9')
                return false;
            if (i < cs.length - 1) {
                power += (cs[i] - '0') * POWER_LIST[i];
            }
        }
        //校验区位码
        if (!zoneNum.containsKey(Integer.valueOf(s.substring(0, 2)))) {
            return false;
        }
        //校验年份
        String year = s.length() == 15 ? "19" + s.substring(6, 8) : s
                .substring(6, 10);
        final int iyear = Integer.parseInt(year);
        if (iyear < 1900 || iyear > Calendar.getInstance().get(Calendar.YEAR))
            return false;//1900年的PASS，超过今年的PASS
        //校验月份
        String month = s.length() == 15 ? s.substring(8, 10) : s.substring(10, 12);
        final int imonth = Integer.parseInt(month);
        if (imonth < 1 || imonth > 12) {
            return false;
        }
        //校验天数
        String day = s.length() == 15 ? s.substring(10, 12) : s.substring(12, 14);
        final int iday = Integer.parseInt(day);
        if (iday < 1 || iday > 31)
            return false;
        //校验一个合法的年月日
        if (!validate(iyear, imonth, iday))
            return false;
        //校验"校验码"
        if (s.length() == 15)
            return true;
        return cs[cs.length - 1] == PARITYBIT[power % 11];
    }

    static boolean validate(int year, int imonth, int iday) {
        //比如考虑闰月，大小月等
        return true;
    }

    /**
     * 通过身份证号得到出生日期
     *
     * @param idCardNo
     * @return
     * @throws Exception
     */
    public static String getBirthDayToIdCard(String idCardNo) throws Exception {
        String birthDay = null;
        try {
            String year = null;
            String month = null;
            String day = null;
            if (idCardNo.length() == 15) {
                year = "19" + idCardNo.substring(6, 8);
                month = idCardNo.substring(8, 10);
                day = idCardNo.substring(10, 12);
            } else if (idCardNo.length() == 18) {
                int i = 6;//截取字符起点
                year = idCardNo.substring(i, i + 4);//截取
                month = idCardNo.substring(i + 4, i + 6);//截取月
                day = idCardNo.substring(i + 6, i + 8);//截取
            }
            birthDay = year + "-" + month + "-" + day;
            return birthDay;
        } catch (Exception e) {//兼容性更强,异常后返回数据
            return null;
        }
    }

    /**
     * 通过出生日期得到年龄
     *
     * @param birthDay
     * @return
     * @throws Exception
     */
    public static int getAgeToBirthDay(Date birthDay) throws Exception {
        int age = 0;
        try {
            Calendar now = Calendar.getInstance();
            now.setTime(new Date());// 当前时间

            Calendar birth = Calendar.getInstance();
            birth.setTime(birthDay);

            if (birth.after(now)) {//如果传入的时间，在当前时间的后面，返回0岁
                age = 0;
            } else {
                age = now.get(Calendar.YEAR) - birth.get(Calendar.YEAR);
                if (now.get(Calendar.DAY_OF_YEAR) > birth.get(Calendar.DAY_OF_YEAR)) {
                    age += 1;
                }
            }
            return age;
        } catch (Exception e) {//兼容性更强,异常后返回数据
            return 0;
        }
    }

    public static int getAge(Date birthDay) throws Exception {
        Calendar cal = Calendar.getInstance();

        if (cal.before(birthDay)) {
            throw new IllegalArgumentException(
                    "The birthDay is before Now.It's unbelievable!");
        }
        int yearNow = cal.get(Calendar.YEAR);
        int monthNow = cal.get(Calendar.MONTH);
        int dayOfMonthNow = cal.get(Calendar.DAY_OF_MONTH);
        cal.setTime(birthDay);

        int yearBirth = cal.get(Calendar.YEAR);
        int monthBirth = cal.get(Calendar.MONTH);
        int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);

        int age = yearNow - yearBirth;

        //不考虑是否过生日
//        if (monthNow <= monthBirth) {
//            if (monthNow == monthBirth) {
//                if (dayOfMonthNow < dayOfMonthBirth) age--;
//            } else {
//                age--;
//            }
//        }
        return age;
    }

    /**
     * 通过身份证号计算年龄
     *
     * @param idNum
     * @return
     */
    public static int IdNOToAge(String idNum) {
        int age = 0;
        GregorianCalendar calendar = new GregorianCalendar(TimeZone.getDefault());//获取系统当前时间
        int currentYear = calendar.get(Calendar.YEAR);
        if (idNum.matches("^\\d{15}$|^\\d{17}[\\dxX]$")) {
            if (idNum.length() == 18) {
                Pattern pattern = Pattern.compile("\\d{6}(\\d{4})\\d{6}(\\d{1})[\\dxX]{1}");
                Matcher matcher = pattern.matcher(idNum);
                if (matcher.matches()) {
                    age = currentYear - Integer.parseInt(matcher.group(1));
                }
            } else if (idNum.length() == 15) {
                Pattern p = Pattern.compile("\\d{6}(\\d{2})\\d{5}(\\d{1})\\d{1}");
                Matcher m = p.matcher(idNum);
                if (m.matches()) {
                    int year = Integer.parseInt(m.group(1));
                    year = 2000 + year;
                    if (year > 2020) {
                        year = year - 100;
                    }
                    age = currentYear - year;
                }
            }
        }

        return age;

    }

    /**
     * 通过身份证获取性别
     *
     * @param idCardNum
     * @return 1男 0 女
     */
    public static int getSexByIdCard(String idCardNum) {
        int idxSexStart = 16;
        //如果是15位的证件号码
        if (idCardNum.length() == 15) {
            idxSexStart = 14;
        }
        String idxSexStr = idCardNum.substring(idxSexStart, idxSexStart + 1);
        int idxSex = Integer.parseInt(idxSexStr) % 2;
//        String sex = (idxSex == 1) ? "男" : "女";
        return idxSex;
    }

    /**
     * 通过身份证号获取个人信息
     *
     * @param idCardNum
     * @return
     */
    public static Map<String, Object> getIdCardInfoByIdCard(String idCardNum) {
        Map<String, Object> map = new HashMap<>();
        try {
            if (isIdcard(idCardNum)) {
                String birthDay = getBirthDayToIdCard(idCardNum);
                int age = IdNOToAge(idCardNum);
                int sexInt = getSexByIdCard(idCardNum);
//                String sex = (sexInt == 1) ? "男" : "女";
                map.put("birthDay", birthDay);
                map.put("age", age);
                map.put("sex", sexInt);
            }
        } catch (Exception e) {
            return null;
        }
        return map;
    }

}
